package com.zpark.merchant.service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zpark.jushanpay.common.domain.BusinessException;
import com.zpark.jushanpay.common.domain.CommonErrorCode;
import com.zpark.jushanpay.common.domain.PageVO;
import com.zpark.jushanpay.common.util.PhoneUtil;
import com.zpark.jushanpay.common.util.StringUtil;
import com.zpark.merchant.api.dto.MerchantDTO;
import com.zpark.merchant.api.dto.StaffDTO;
import com.zpark.merchant.api.dto.StoreDTO;
import com.zpark.merchant.service.convert.IStaffConvert;
import com.zpark.merchant.service.convert.IStoreConvert;
import com.zpark.merchant.service.convert.IStoreStaffConvert;
import com.zpark.merchant.service.convert.MerchantConvert;
import com.zpark.merchant.service.entity.Merchant;
import com.zpark.merchant.service.entity.Staff;
import com.zpark.merchant.service.entity.Store;
import com.zpark.merchant.service.entity.StoreStaff;
import com.zpark.merchant.service.mapper.IMerchantMapper;
import com.zpark.merchant.api.service.IMerchantService;
import com.zpark.merchant.service.mapper.IStaffMapper;
import com.zpark.merchant.service.mapper.IStoreMapper;
import com.zpark.merchant.service.mapper.IStoreStaffMapper;
import com.zpark.user.api.dto.tenant.TenantDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 商户业务层实现类
 */
@Service
public class MerchantServiceImpl implements IMerchantService {

    @Autowired
    private IMerchantMapper merchantMapper;
    @Autowired
    private IStoreMapper storeMapper;
    @Autowired
    private IStaffMapper staffMapper;
    @Autowired
    private IStoreStaffMapper storeStaffMapper;
    @Autowired
    private RestTemplate restTemplate;

    // 定义远程调用服务的url
    @Value("${saas.user.tenant.url}")
    String url;

    /**
     * 根据商户ID查询数据
     * @param id 商户的id
     * @return 商户对象
     */
    @Override
    public MerchantDTO findById(Long id) {
        // 调用持久层接口产线数据
        Merchant merchant = merchantMapper.selectById(id);

        // 给dto赋值
        MerchantDTO dto = new MerchantDTO();
        dto.setId(merchant.getId());
        dto.setMerchantName(merchant.getMerchantName());
        // 其他属性赋值

        return dto;
    }

    /**
     * 注册商户服务接口，接收账号、密码、手机号，
     * 为了可扩展性使用merchantDto接收数据
     * @param dto 商户注册对象
     * @return
     */
    @Override
    // 开启事务
    @Transactional
    public MerchantDTO createMerchant(MerchantDTO dto) {
        // 1、MerchantDTO是否为null
        if (dto == null) {
            throw new BusinessException(CommonErrorCode.E_100108);
        }
        // 校验手机号是否为空
        if (dto.getMobile() == null) {
            throw new BusinessException(CommonErrorCode.E_100112);
        }
        // 校验手机号是否满足要求
        if (!PhoneUtil.isMatches(dto.getMobile())) {
            throw new BusinessException(CommonErrorCode.E_100109);
        }
        // 校验是否有联系人姓名
        if (StringUtil.isBlank(dto.getUsername())) {
            throw new BusinessException(CommonErrorCode.E_100110);
        }
        // 校验密码是否为空
        if (StringUtil.isBlank(dto.getPassword())) {
            throw new BusinessException(CommonErrorCode.E_100111);
        }
        // 校验商户手机号的唯一性,根据商户的手机号查询商户表，如果存在记录则说明已有相同的手机号重复
        // 创建条件构造器
        QueryWrapper<Merchant> wrapper = new QueryWrapper<Merchant>()
                .eq("mobile", dto.getMobile());
        // 调用持久层接口查询数据
        Long count = merchantMapper.selectCount(wrapper);

        if (count > 0) {
            throw new BusinessException(CommonErrorCode.E_100113);
        }

        // 创建租户（调用SaaS服务）
        // 构建请求参数对象
        Map<String, Object> body = new HashMap<>();
        body.put("name", dto.getUsername());
        body.put("tenantTypeCode", "jushanpay-merchant");
        body.put("bundleCode", "jushanpay-merchant");
        body.put("mobile", dto.getMobile());
        body.put("password", dto.getPassword());
        body.put("username", dto.getUsername());

        // 创建http请求头
        HttpHeaders httpHeaders = new HttpHeaders();
        // 设置请求头类型为json
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);

        // 实体（请求参数载体）
        HttpEntity entity = new HttpEntity(body, httpHeaders);

        // 发起远程调用服务接口
        TenantDTO tenantDTO = restTemplate.postForObject(url, entity, TenantDTO.class);

        // 判断租户是否创建成功
        if (tenantDTO == null) {
            // 创建租户失败
            throw new BusinessException(CommonErrorCode.E_200024);
        }

        // 根据租户的id查询商户数据
        Long row = merchantMapper.selectCount(
                new LambdaQueryWrapper<Merchant>()
                        .eq(Merchant::getTenantId, tenantDTO.getId())
        );

        // 判断租户是否注册商户
        if (row > 0) {
            // 租户已经注册过商户
            throw new BusinessException(CommonErrorCode.E_200017);
        }

        // 2、将dto转为merchant对象
        Merchant merchant = MerchantConvert.INSTANCE.merchantDtoToMerchant(dto);
        // 设置审核状态 0-未申请  1-已申请未审核 2-审核通过  3-审核不通过
        merchant.setAuditStatus("0");
        // 设置租户id
        merchant.setTenantId(tenantDTO.getId());

        // 3、调用持久层接口添加数据
        merchantMapper.insert(merchant);

        // 4、创建门店
        StoreDTO storeDTO = new StoreDTO();
        storeDTO.setStoreName("根门店");
        storeDTO.setMerchantId(merchant.getId());

        // 调用创建门店方法插入数据
        StoreDTO store = createStore(storeDTO);

        // 创建员工
        StaffDTO staffDTO = new StaffDTO();
        staffDTO.setMerchantId(merchant.getId());
        staffDTO.setUsername(merchant.getUsername());
        staffDTO.setMobile(merchant.getMobile());
        staffDTO.setStoreId(store.getId());

        // 调用创建员工方法插入数据
        StaffDTO staff = createStaff(staffDTO);

        // 设置门店管理员,调用设置管理员方法
        bindStoreAndStaff(store.getId(), staff.getId());

        // 将merchant对象转为Dto
        dto = MerchantConvert.INSTANCE.merchantToMerchantDto(merchant);

        return dto;
    }

    /**
     * 商户资质申请业务层接口
     * @param merchantId 商户id
     * @param dto 商户资质申请对象
     * @throws BusinessException
     */
    @Override
    @Transactional
    public void applyMerchant(Long merchantId, MerchantDTO dto) throws BusinessException {
        // 判断商户dto是否为空
        if (dto == null) {
            throw new BusinessException(CommonErrorCode.E_100108);
        }
        // 根据商户id查询数据
        Merchant merchant = merchantMapper.selectById(merchantId);
        if (merchant == null) {
            throw new BusinessException(CommonErrorCode.E_200002);
        }
        // 将dto转为merchant对象
        Merchant merchant_update = MerchantConvert.INSTANCE.merchantDtoToMerchant(dto);
        // 设置id
        merchant_update.setId(merchant.getId());
        // 设置联系人姓名
        merchant_update.setUsername(merchant.getUsername());

        // 设置申请状态
        // 审核状态 0-未申请,1-已申请待审核,2-审核通过,3-审核拒绝
        merchant_update.setAuditStatus("1");
        // 设置租户ID
        merchant_update.setTenantId(merchant.getTenantId());

        // 将数据更新到数据表
        merchantMapper.updateById(merchant_update);
    }

    /**
     * 商户创建门店
     * @param dto 门店对象
     * @return
     * @throws BusinessException
     */
    @Override
    @Transactional
    public StoreDTO createStore(StoreDTO dto) throws BusinessException {
        // 将dto转为entity
        Store store = IStoreConvert.INSTANCE.dtoToEntity(dto);
        // 调用持久层接口
        storeMapper.insert(store);
        // 返回dto
        return IStoreConvert.INSTANCE.entityToDto(store);
    }

    /**
     * 创建员工对象
     * @param dto 员工对象
     * @return
     * @throws BusinessException
     */
    @Override
    @Transactional
    public StaffDTO createStaff(StaffDTO dto) throws BusinessException {
        // 校验员工手机号格式是否正确
        if (!PhoneUtil.isMatches(dto.getMobile())) {
            // 手机号格式错误
            throw new BusinessException(CommonErrorCode.E_200224);
        }
        // 根据商户id和手机号确定员工的唯一性（判断手机号是否被使用）
        if (isExistsMerchantIdPhone(dto.getMobile(), dto.getMerchantId())) {
            // 手机号被占用
            throw new BusinessException(CommonErrorCode.E_200203);
        }
        // 判断用户名字是否为空
        if (StringUtil.isEmpty(dto.getUsername())) {
            throw new BusinessException(CommonErrorCode.E_200231);
        }
        // 根据商户id和员工名字确定是否唯一（判断用户名是否被使用）
        if (isExistsMerchantIdUsername(dto.getUsername(), dto.getMerchantId())) {
            // 用户名被占用
            throw new BusinessException(CommonErrorCode.E_200225);
        }
        // 将dto转为entity
        Staff staff = IStaffConvert.INSTANCE.dtoToEntity(dto);
        // 调用持久层接口插入数据
        staffMapper.insert(staff);
        // 返回dto
        return IStaffConvert.INSTANCE.entityToDto(staff);
    }

    /**
     * 商户设置管理员
     * @param storeId 门店id
     * @param staffId 员工id（管理员id）
     * @throws BusinessException
     */
    @Override
    @Transactional
    public void bindStoreAndStaff(Long storeId, Long staffId) throws BusinessException {
        // 创建storeStaff对象
        StoreStaff storeStaff = new StoreStaff();
        // 设置数据
        storeStaff.setStaffId(staffId);
        storeStaff.setStoreId(storeId);
        // 调用持久层方法插入数据
        storeStaffMapper.insert(storeStaff);
    }

    /**
     * 根据商户的id查询门店的分页信息
     * @param storeDTO 门店信息
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public PageVO<StoreDTO> queryStoreByMerchantId(StoreDTO storeDTO, Integer pageNo, Integer pageSize) {
        // 创建分页对象
        Page<Store> page = new Page<>();
        // 查询数据，查数据之前需要判断dto和merchantId是否为空
        Page<Store> storePage = null;
        if (storeDTO != null && storeDTO.getMerchantId() != null) {
            storePage = storeMapper.selectPage(page,
                    new LambdaQueryWrapper<Store>()
                            .eq(Store::getMerchantId, storeDTO.getMerchantId()));
        }
        // 获取分页列表查询数据
        List<Store> storeList = storePage.getRecords();
        // 将entity转为dto返回
        List<StoreDTO> storeDTOS = IStoreConvert.INSTANCE.listEntityToListDto(storeList);

        // 返回分页信息
        return new PageVO<>(storeDTOS, storePage.getTotal(), pageNo, pageSize);
    }

    /**
     * 根据门店id和商户id查询门店是否存在
     * @param storeId 门店id
     * @param merchantId 商户ID
     * @return
     */
    @Override
    public Boolean queryStoreIdInMerchantId(Long storeId, Long merchantId) {
        // 根据门店id和商户id查询门店数据
        Long count = storeMapper.selectCount(
                new LambdaQueryWrapper<Store>()
                        .eq(Store::getId, storeId)
                        .eq(Store::getMerchantId, merchantId)
        );
        // 判断查询结果，有数据返回true，没有则返回false
        return count > 0;
    }


    /**
     * 判断商户id和手机号是否唯一
     * @param phone 手机号
     * @param merchantId 商户的id
     * @return true 表示手机也存在
     */
    private Boolean isExistsMerchantIdPhone(String phone, Long merchantId){
        // 调用持久层方法查询数据
        Long count = staffMapper.selectCount(
                new LambdaQueryWrapper<Staff>()
                        .eq(Staff::getMobile, phone)
                        .eq(Staff::getMerchantId, merchantId)
        );
        return count > 0;
    }

    /**
     * 判断商户id和用户名是否唯一
     * @param username 手机号
     * @param merchantId 商户的id
     * @return true 表示手机也存在
     */
    private Boolean isExistsMerchantIdUsername(String username, Long merchantId){
        // 调用持久层方法查询数据
        Long count = staffMapper.selectCount(
                new LambdaQueryWrapper<Staff>()
                        .eq(Staff::getUsername, username)
                        .eq(Staff::getMerchantId, merchantId)
        );
        return count > 0;
    }
}
